package com.kx.yooli.kx.wechat.utils.http;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.google.common.base.Strings;
import com.kx.yooli.kx.wechat.base.CompanyCodeEnum.CompanyCodeEnum;
import com.kx.yooli.kx.wechat.base.mdc.TransferMDC;
import com.kx.yooli.kx.wechat.config.propertiesconf.CustomizedPropertyConfigurer;
import com.kx.yooli.kx.wechat.constant.HeaderConstants;
import com.kx.yooli.kx.wechat.utils.date.DateTimeUtil;
import com.kx.yooli.kx.wechat.utils.log.LogMonitorUtil;
import com.kx.yooli.kx.wechat.utils.security.MD5Util;
import com.kx.yooli.kx.wechat.utils.uuid.RandomUtil;
import com.kx.yooli.kx.wechat.utils.uuid.UUIDGenerator;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import java.io.*;
import java.net.InetAddress;
import java.net.URLDecoder;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * @author john_sqwen-childe.wen
 * date 2024/4/8
 * PROJECT_NAME wechat
 * description create HttpSenderUtil by john_sqwen
 * and  value is
 */
public class HttpSenderUtil {
    private final static Logger log = LoggerFactory.getLogger(HttpSenderUtil.class);
    /**
     *
     * @param url 应用地址，类似于http://ip:port/msg/
     * @param account 账号
     * @param pswd 密码
     * @param mobile 手机号码，多个号码使用","分割
     * @param msg 短信内容
     * @param needstatus 是否需要状态报告，需要true，不需要false
     * @return 返回值定义参见HTTP协议文档
     * @throws Exception
     */
    public static String send(String url, String account, String pswd, String mobile, String msg,
                              boolean needstatus, String product, String extno) throws Exception {
        HttpClient client = new HttpClient();
        GetMethod method = new GetMethod();
        try {
            URI base = new URI(url, false);
            method.setURI(new URI(base, "HttpSendSM", false));
            method.setQueryString(new NameValuePair[] {
                    new NameValuePair("account", account),
                    new NameValuePair("pswd", pswd),
                    new NameValuePair("mobile", mobile),
                    new NameValuePair("needstatus", String.valueOf(needstatus)),
                    new NameValuePair("msg", msg),
                    new NameValuePair("product", product),
                    new NameValuePair("extno", extno),
            });

            addHeaderOfTraceId(method);

            int result = client.executeMethod(method);
            if (result == HttpStatus.SC_OK) {
                InputStream in = method.getResponseBodyAsStream();
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                byte[] buffer = new byte[1024];
                int len = 0;
                while ((len = in.read(buffer)) != -1) {
                    baos.write(buffer, 0, len);
                }
                return URLDecoder.decode(baos.toString(), "UTF-8");
            } else {
                throw new Exception("HTTP ERROR Status: " + method.getStatusCode() + ":" + method.getStatusText());
            }
        } finally {
            method.releaseConnection();
        }

    }

    /**
     *
     * @param url 应用地址，类似于http://ip:port/msg/
     * @param account 账号
     * @param pswd 密码
     * @param mobile 手机号码，多个号码使用","分割
     * @param msg 短信内容
     * @param needstatus 是否需要状态报告，需要true，不需要false
     * @return 返回值定义参见HTTP协议文档map 包括日志文档
     * @throws Exception
     */
    public static Map batchSend(String url, String account, String pswd, String mobile, String msg,
                                boolean needstatus, String product, String extno) throws Exception {
        Map<String, Object> map = new HashMap<String,Object>();
        HttpClient client = new HttpClient();
        GetMethod method = new GetMethod();
        try {
            URI base = new URI(url, false);
            method.setURI(new URI(base, "HttpBatchSendSM", false));
            method.setQueryString(new NameValuePair[] {
                    new NameValuePair("account", account),
                    new NameValuePair("pswd", pswd),
                    new NameValuePair("mobile", mobile),
                    new NameValuePair("needstatus", String.valueOf(needstatus)),
                    new NameValuePair("msg", msg),
                    new NameValuePair("product", product),
                    new NameValuePair("extno", extno),
            });

            addHeaderOfTraceId(method);

            int result = client.executeMethod(method);
            //记录发送状态
            map.put("status",method.getStatusCode()+"");

            if (result == HttpStatus.SC_OK) {
                InputStream in = method.getResponseBodyAsStream();
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                byte[] buffer = new byte[1024];
                int len = 0;
                while ((len = in.read(buffer)) != -1) {
                    baos.write(buffer, 0, len);
                }
                map.put("log", URLDecoder.decode(baos.toString(), "UTF-8"));

            } else {
                map.put("log",method.getStatusText() );//记录错误描述
                throw new Exception("HTTP ERROR Status: " + method.getStatusCode() + ":" + method.getStatusText());
            }
        } finally {
            method.releaseConnection();
        }

        return map;
    }

    /**
     * @param mobile  手机号码，多个号码使用","分割
     * @param msg "亲爱的用户，您的验证码是123456，5分钟内有效。"; 短信内容
     * @param needstatus 是否需要状态报告，需要true，不需要false
     * @param product 产品ID
     * @param extno 扩展码
     * @return 返回值定义参见HTTP协议文档
     * @throws Exception
     */
    public static Map<?,?> validateMessageSend(String mobile, String msg,
                                          boolean needstatus, String product, String extno)throws Exception{
        Map<String, Object> map = null;
        // String url = "http://222.73.117.158/msg/";// 应用地址
        // String account = "询问对接人";// 账号
        // String pswd = "询问对接人";// 密码

        // 文件在class的根路径
        InputStream is = HttpSenderUtil.class.getClassLoader()
                .getResourceAsStream("message.properties");
        // 获取文件的位置
//		String filePath = HttpSenderUtil.class.getClassLoader()
//				.getResource("message.properties").getFile();
//		System.out.println(filePath);
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        Properties props = new Properties();

        try {
            props.load(br);
            //以下三个参数是系统配置文件自定义参数
            String url = props.getProperty("url"); // 应用地址
            String account = props.getProperty("account");// 账号
            String pswd = props.getProperty("pswd");// 密码

            map = HttpSenderUtil.batchSend(url, account, pswd,
                    mobile, msg, needstatus, product, extno);

        } catch (IOException e) {
            // TODO 处理解析异常
            e.printStackTrace();
        } catch (Exception e) {
            // TODO 处理发送异常
            e.printStackTrace();
        }
        return map;
    }
//	public static void main(String[] args) throws Exception {
////		Map<String, Object> map = null;
////		map = HttpSenderUtil.validateMessageSend("17701812626", "你好，你的验证码是：123456，10分钟内有效",true, null,null);
////		System.out.println(map.get("status")+"=="+map.get("log"));
//		String url = CustomizedPropertyConfigurer.getContextProperty("url.sms.service").toString();
//		String secretKey = CustomizedPropertyConfigurer.getContextProperty("sms.secretKey").toString();
//		Map<String,String> params=new HashMap<String, String>();
//		String smsId = UUIDGenerator.generate(DateTimeUtil.getDate());
//		String sign = MD5Util.MD5(smsId+"&"+CompanyCodeEnum.KX+"&"+"13193299919"+"&"+"您本次操作的验证码为：123456，5分钟内有效"+"&"+secretKey);
//		params.put("smsId", smsId);
//		params.put("companyCode", CompanyCodeEnum.KX.toString());
//		params.put("mobile", "13193299919");
//		params.put("content", "您本次操作的验证码为：123456，5分钟内有效");
//		params.put("sendTime", String.valueOf(System.currentTimeMillis()));
//		params.put("smsType", "666");
//		params.put("ip", InetAddress.getLocalHost().getHostAddress());
//		params.put("sign", sign);
//		params.put("verificationCode", "123456");
//		String result=HttpUtils.URLPost(url, params, "utf-8");
//		System.out.println(result);
//
//	}

    public static  JSONObject sendMessageSend(String mobilePhone,
                                              String content, String checkcode) throws Exception {
        String url = CustomizedPropertyConfigurer.getContextProperty("new.sms.service.url").toString();
        String secretKey = CustomizedPropertyConfigurer.getContextProperty("new.sms.service.secretKey").toString();
        Map<String,Object> params=new HashMap<String, Object>();
        String smsId = UUIDGenerator.generate(DateTimeUtil.getDate());
        String sign = MD5Util.MD5(smsId+"&"+CompanyCodeEnum.KX+"&"+mobilePhone+"&"+content+"&"+secretKey);
        params.put("smsId", smsId);
        params.put("companyCode", CompanyCodeEnum.KX.toString());
        params.put("mobile", mobilePhone);
        params.put("content", content);
        params.put("sendTime", System.currentTimeMillis());
        params.put("smsType", 9533);
        params.put("ip", InetAddress.getLocalHost().getHostAddress());
        params.put("sign", sign);
        params.put("verificationCode", checkcode);
        log.info(mobilePhone + "短信入参:"+params);
        String json  = JSONObject.toJSONString(params);
        String response = smsPost(url, json);

        log.info(mobilePhone + "短信返回结果:"+response);
        JSONObject jSONObject = JSONObject.parseObject(response);
        return jSONObject;
    }

    private static String smsPost(String url, String json) throws Exception{
        CloseableHttpClient httpClient = createSSLClientDefault();
        HttpPost method = new HttpPost(url);
        try {
            StringEntity entity = new StringEntity(json, "utf-8");
            entity.setContentEncoding("UTF-8");
            entity.setContentType("application/json");
            method.setEntity(entity);

            String tradeId = TransferMDC.getValue(HeaderConstants.LEGACY_TRACE_ID_NAME);
            if (Strings.isNullOrEmpty(tradeId)) {
                tradeId = RandomUtil.generateTraceId();
            }
            String requestUri = null;
            try {
                requestUri = method.getRequestLine().getUri();
            } catch (Exception e) {
                requestUri = HeaderConstants.HEADER_LINE_THROUGH;
            }
            if(Strings.isNullOrEmpty(requestUri)){
                requestUri = HeaderConstants.HEADER_LINE_THROUGH;
            }
            method.addHeader(HeaderConstants.LEGACY_TRACE_ID_NAME, tradeId);
            method.addHeader(HeaderConstants.X_KX_REQUEST_URI, requestUri);

            LogMonitorUtil.generateBusinessLog(url, HttpSenderUtil.class, "smsPost", "url:"+url);
            HttpResponse result = httpClient.execute(method);
            String str = "";
            if (result.getStatusLine().getStatusCode() == 200) {
                str = EntityUtils.toString(result.getEntity());
            }else if(result.getStatusLine().getStatusCode() == 403){
                str = "403";
            }
            return str;
        } catch (Exception e) {
            log.error("Send sms code encounter error:",e);
            LogMonitorUtil.generateExceptionLog(url, HttpSenderUtil.class, "smsPost", "url:"+url, e);
            throw e;
        }finally {
            httpClient.close();
        }
    }

    /**
     * 不需要导入证书，SSL信任所有证书，使用该方法
     *
     * @return
     */
    public static CloseableHttpClient createSSLClientDefault() {
        try {
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
                // 信任所有证书
                public boolean isTrusted(X509Certificate[] chain,
                                         String authType) throws CertificateException {
                    return true;
                }
            }).build();

            //超时时间 10秒
            RequestConfig defaultRequestConfig =
                    RequestConfig.custom().setSocketTimeout(10000).setConnectTimeout(10000)
                            .setConnectionRequestTimeout(10000).build();

            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
            return HttpClients.custom().setDefaultRequestConfig(defaultRequestConfig).setSSLSocketFactory(sslsf).build();
        } catch (KeyManagementException e) {
            log.warn("Send sms code encounter error:",e);
        } catch (NoSuchAlgorithmException e) {
            log.warn("Send sms code encounter error:",e);
        } catch (KeyStoreException e) {
            log.warn("Send sms code encounter error:",e);
        }
        return HttpClients.createDefault();
    }

    private static void addHeaderOfTraceId(HttpMethod request){
        String tradeId = TransferMDC.getValue(HeaderConstants.LEGACY_TRACE_ID_NAME);
        if (Strings.isNullOrEmpty(tradeId)) {
            tradeId = RandomUtil.generateTraceId();
        }
        String requestUri = null;
        try {
            requestUri = request.getURI().getURI();
        } catch (Exception e) {
            requestUri = HeaderConstants.HEADER_LINE_THROUGH;
        }
        if(Strings.isNullOrEmpty(requestUri)){
            requestUri = HeaderConstants.HEADER_LINE_THROUGH;
        }

        request.addRequestHeader(HeaderConstants.LEGACY_TRACE_ID_NAME, tradeId);
        request.addRequestHeader(HeaderConstants.X_KX_REQUEST_URI, requestUri);
    }

    /**
     * 调用新接口发送短信验证码
     * @param mobile 手机号
     * @param custFamilyName 姓
     * @param sex 先生/女士
     * @param salerName 销售名字
     * @return
     */
    public static JSONObject sendResignSANotify(String mobile, String custFamilyName, String sex, String salerName) throws Exception{
        String url = (String) CustomizedPropertyConfigurer.getContextProperty("new.sms.service.url");
        String secretKey =(String) CustomizedPropertyConfigurer.getContextProperty("new.sms.service.secretKey");
        String smsTempId = (String) CustomizedPropertyConfigurer.getContextProperty("new.sms.service.resignSa.tempId");
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("familyName", custFamilyName);
        paramMap.put("salerName", salerName);
        paramMap.put("sex", sex);
        String param = JSON.toJSONString(paramMap);
        Map<String, Object> params = new HashMap<>(8);
        String sign = MD5Util.MD5(smsTempId + "&" + param + "&" + mobile + "&" + secretKey);
        params.put("smsId", UUIDGenerator.generate(DateTimeUtil.getDate()));
        params.put("smsTempId", smsTempId);
        params.put("mobile", mobile);
        params.put("paramMap", param);
        params.put("sendTime", System.currentTimeMillis());
        params.put("ip", InetAddress.getLocalHost().getHostAddress());
        params.put("sign",sign);
        log.info("发送离职SA通知短信入参:"+params);
        String json  = JSONObject.toJSONString(params);
        String response = smsPost(url, json);
        log.info("发送离职SA通知短信返回结果:"+response);
        return  JSONObject.parseObject(response);
    }

    /**
     * 调用新接口发送绑定短信验证码
     * @param mobile 手机号
     * @return
     */
    public static JSONObject sendBindCheckCode(String mobile, String checkCode) throws Exception{
//        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//        //检查发送次数
//        Integer allSendTimes = (Integer) RedisUtil.getRedisCache("kx-public-wechat-sms-sendTime:" + sdf.format(new Date()));
//        if (allSendTimes != null && allSendTimes >= (Integer) CustomizedPropertyConfigurer.getContextProperty("sms.send.times.limit.all")){
//            throw new ServiceException(ServiceErrorCode.ERROR,"超过每日短信发送次数限制");
//        }
//        Integer singleSendTimes = (Integer) RedisUtil.getRedisCache("kx-public-wechat-sms-sendTime:" + sdf.format(new Date()) + ":" + mobile);
//        if (singleSendTimes != null && singleSendTimes >= (Integer) CustomizedPropertyConfigurer.getContextProperty("sms.send.times.limit.single")){
//            throw new ServiceException(ServiceErrorCode.ERROR,"超过每日短信发送次数限制");
//        }
        String url = (String) CustomizedPropertyConfigurer.getContextProperty("new.sms.service.url");
        String secretKey =(String) CustomizedPropertyConfigurer.getContextProperty("new.sms.service.secretKey");
        String smsTempId = (String) CustomizedPropertyConfigurer.getContextProperty("new.sms.service.resignSa.tempId");
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("checkCode", checkCode);
        String param = JSON.toJSONString(paramMap);
        Map<String, Object> params = new HashMap<>(8);
        String sign = MD5Util.MD5(smsTempId + "&" + param + "&" + mobile + "&" + secretKey);
        params.put("smsId", UUIDGenerator.generate(DateTimeUtil.getDate()));
        params.put("smsTempId", smsTempId);
        params.put("mobile", mobile);
        params.put("paramMap", param);
        params.put("sendTime", System.currentTimeMillis());
        params.put("ip", InetAddress.getLocalHost().getHostAddress());
        params.put("sign",sign);
        log.info("发送绑定短信验证码入参:"+params);
        String json  =  JSONObject.toJSONString(params);
        String response = smsPost(url, json);
        log.info("发送绑定短信验证码返回结果:"+response);
//        if (sendResult != null || 0 == sendResult.getIntValue("resultCode")){
//            allSendTimes = allSendTimes == null? 1:allSendTimes;
//            allSendTimes++;
//            RedisUtil.setRedisCache("kx-public-wechat-sms-sendTime" + sdf.format(new Date()), allSendTimes);
//            singleSendTimes = singleSendTimes == null? 1: singleSendTimes;
//            singleSendTimes++;
//            RedisUtil.setRedisCache("kx-public-wechat-sms-sendTime:" + sdf.format(new Date()) + ":" + mobile, singleSendTimes);
//        }
        return  JSONObject.parseObject(response);
    }

    public static void main(String[] args) throws Exception {
        sendResignSANotify("17628298180", "杨", "先生", "张三");
    }
}
